#ifndef SC_SETUP_H_INCLUDED
#define SC_SETUP_H_INCLUDED

#include "sc/config.h"

#include <libxml/xmlwriter.h>

#include <set>

namespace sc {

class Setup
{
public:
	Setup();
	~Setup();

public:
	/**
	* Class Attribute
	*/
	class Attribute
	{
	public:
		Attribute(const std::string& val, const Config::Attribute& rcConf)
			: m_sValue(val), m_rcConf(rcConf) {}

		std::string               m_sValue;
		const Config::Attribute&  m_rcConf;
	};

	/**
	* Class Element
	*/
	class Element;
	typedef std::list<Element> TListElement;
	typedef std::map<std::string,Attribute> TMapAttribut;

	class Element
	{
	public:
		Element(const std::string& name = "", const std::string& content = "");
		Element(const std::string& name, const std::string& content, Config::TMapElement::const_iterator iter);
		~Element();

	protected:
        /// Setup attributes
		std::string m_sName;
		std::string m_sContent;

		TMapAttribut m_attributes;
		TListElement m_children;

		Config::TMapElement::const_iterator  m_config;

	public:
        /// Setup Element public methods
		int AddChild(const Element& rcElement, TListElement::iterator& rIterChild);
		int AddChild(const Element& rcElement);
		int AddUniqueChildren(void);

		bool IsValid(void) const;
		bool IsChildAvailable(const std::string& sChildName) const;
		void GetAvailableChildren(std::set<std::string>& rListChild) const;

		const std::string GetName(void) const { return m_sName; }
		const std::string GetContent(void) const { return m_sContent; }
		const TMapAttribut& GetAttributes(void) const { return m_attributes; }
		const TListElement& GetChildren(void) const { return m_children; }

		TListElement::iterator ChildrenBegin(void) { return m_children.begin(); }
		TListElement::iterator ChildrenEnd(void) { return m_children.end(); }

		TMapAttribut::iterator AttributesBegin(void) { return m_attributes.begin(); }
		TMapAttribut::iterator AttributesEnd(void) { return m_attributes.end(); }

		Config::TMapElement::const_iterator GetConfig(void) const { return m_config; }

		int Delete(const Element* pcElement);

		int Save(xmlTextWriterPtr xmlWriter) const;

	protected:
		/**
		* Predicate to find a child configuration by name
		*/
		class PredFindConfigChildName
		{
		public:
			PredFindConfigChildName(const std::string& name)
				: m_name(name) {}

		protected:
			std::string m_name;

		public:
			bool operator() (const Config::TListChild::value_type& val)
			{ return (*val).second.sName == m_name; }
		};

		/**
		* Predicate to find if a child exist
		*/
		class PredFindChildName
		{
		public:
			PredFindChildName(const std::string& name)
				: m_name(name) {}

		protected:
			std::string m_name;

		public:
			bool operator() (const TListElement::value_type& val)
			{ return val.m_sName == m_name; }
		};
	};

protected:
	Config  m_config;
	Element* m_pRoot;

public:
	const Config& GetConfig(void) const { return m_config; }
	const Element* Get(void) const { return m_pRoot; }
	Element* Get(void) { return m_pRoot; }

	int LoadConfig(const std::string& sConfigFilename);
	int Load(const std::string& sFilename);
	int Save(const std::string& sFilename) const;

	int DeleteElement(const Element* pcElement);

	void Clear(void);

protected:
    int AddUniqueChildren(Element& rElement);
};

};

#endif //  SC_SETUP_H_INCLUDED
